home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 1 / QRZ Ham Radio Callsign Database - December 1993.iso / ucsd / packet / tcpip / sys5 / iscwmpst.z / iscwmpst / tcp / isc-src / convers / conversd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-29  |  30.5 KB  |  1,176 lines

  1. static char  rcsid[] = "@(#) $Header: conversd.c,v 2.17 91/06/17 14:13:37 deyke Exp $";
  2.  
  3. #define _HPUX_SOURCE
  4.  
  5. #include <sys/types.h>
  6.  
  7. #include <ctype.h>
  8. #include <fcntl.h>
  9. #include <signal.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <sys/socket.h>
  14. #include <sys/stat.h>
  15. #include <sys/utsname.h>
  16. #include <time.h>
  17. #include <unistd.h>
  18. #include <utmp.h>
  19.  
  20. extern struct utmp *getutent();
  21. extern void endutent();
  22.  
  23. #ifdef __STDC__
  24. #define __ARGS(x)       x
  25. #else
  26. #define __ARGS(x)       ()
  27. #endif
  28.  
  29. #include "buildsaddr.h"
  30.  
  31. #define MAXCHANNEL 32767
  32.  
  33. struct mbuf {
  34.   struct mbuf *next;
  35.   char  *data;
  36. };
  37.  
  38. #define NULLMBUF  ((struct mbuf *) 0)
  39.  
  40. struct connection {
  41.   int  type;                    /* Connection type */
  42. #define CT_UNKNOWN      0
  43. #define CT_USER         1
  44. #define CT_HOST         2
  45. #define CT_CLOSED       3
  46.   char  name[80];               /* Name of user or host */
  47.   char  host[80];               /* Name of host where user is logged on */
  48.   struct connection *via;       /* Pointer to neighbor host */
  49.   int  channel;                 /* Channel number */
  50.   long  time;                   /* Connect time */
  51.   int  locked;                  /* Set if mesg already sent */
  52.   int  fd;                      /* Socket descriptor */
  53.   int  fmask;                   /* Socket mask */
  54.   char  ibuf[2048];             /* Input buffer */
  55.   int  icnt;                    /* Number of bytes in input buffer */
  56.   struct mbuf *obuf;            /* Output queue */
  57.   int  received;                /* Number of bytes received */
  58.   int  xmitted;                 /* Number of bytes transmitted */
  59.   struct connection *next;      /* Linked list pointer */
  60. };
  61.  
  62. #define CM_UNKNOWN   (1 << CT_UNKNOWN)
  63. #define CM_USER      (1 << CT_USER)
  64. #define CM_HOST      (1 << CT_HOST)
  65. #define CM_CLOSED    (1 << CT_CLOSED)
  66.  
  67. #define NULLCONNECTION  ((struct connection *) 0)
  68.  
  69. struct permlink {
  70.   char  name[80];               /* Name of host */
  71.   char  socket[80];             /* Name of socket to connect to */
  72.   char  command[256];           /* Optional connect command */
  73.   struct connection *connection;/* Pointer to associated connection */
  74.   long  statetime;              /* Time of last (dis)connect */
  75.   int  tries;                   /* Number of connect tries */
  76.   long  waittime;               /* Time between connect tries */
  77.   long  retrytime;              /* Time of next connect try */
  78.   struct permlink *next;        /* Linked list pointer */
  79. };
  80.  
  81. #define NULLPERMLINK  ((struct permlink *) 0)
  82.  
  83. struct utsname utsname;
  84.  
  85. static char  *myhostname;
  86. static long  currtime;
  87. static struct connection *connections;
  88. static struct permlink *permlinks;
  89.  
  90. static void sigpipe_handler __ARGS((int sig, int code, struct sigcontext *scp));
  91. static void appendstring __ARGS((struct mbuf **bpp, char *string));
  92. static int queuelength __ARGS((struct mbuf *bp));
  93. static void freequeue __ARGS((struct mbuf **bpp));
  94. static void free_connection __ARGS((struct connection *cp));
  95. static void free_closed_connections __ARGS((void));
  96. static char *getarg __ARGS((char *line, int all));
  97. static char *formatline __ARGS((char *prefix, char *text));
  98. static char *timestring __ARGS((long gmt));
  99. static struct connection *alloc_connection __ARGS((int fd));
  100. static void accept_connect_request __ARGS((int flisten));
  101. static void clear_locks __ARGS((void));
  102. static void send_user_change_msg __ARGS((char *name, char *host, int oldchannel, int newchannel));
  103. static void send_msg_to_user __ARGS((char *fromname, char *toname, char *text));
  104. static void send_msg_to_channel __ARGS((char *fromname, int channel, char *text));
  105. static void send_invite_msg __ARGS((char *fromname, char *toname, int channel));
  106. static void update_permlinks __ARGS((char *name, struct connection *cp));
  107. static void connect_permlinks __ARGS((void));
  108. static void bye_command __ARGS((struct connection *cp));
  109. static void channel_command __ARGS((struct connection *cp));
  110. static void help_command __ARGS((struct connection *cp));
  111. static void invite_command __ARGS((struct connection *cp));
  112. static void links_command __ARGS((struct connection *cp));
  113. static void msg_command __ARGS((struct connection *cp));
  114. static void name_command __ARGS((struct connection *cp));
  115. static void who_command __ARGS((struct connection *cp));
  116. static void h_cmsg_command __ARGS((struct connection *cp));
  117. static void h_host_command __ARGS((struct connection *cp));
  118. static void h_invi_command __ARGS((struct connection *cp));
  119. static void h_umsg_command __ARGS((struct connection *cp));
  120. static void h_user_command __ARGS((struct connection *cp));
  121. static void process_input __ARGS((struct connection *cp));
  122. static void read_configuration __ARGS((void));
  123.  
  124. /*---------------------------------------------------------------------------*/
  125.  
  126. #define uchar(c)  ((unsigned char) (c))
  127.  
  128. /*---------------------------------------------------------------------------*/
  129. #if (defined(HPUX)||defined(BSD))
  130. static void sigpipe_handler(sig, code, scp)
  131. int  sig, code;
  132. struct sigcontext *scp;
  133. {
  134.   scp->sc_syscall_action = SIG_RETURN;
  135. }
  136. #endif
  137. /*---------------------------------------------------------------------------*/
  138.  
  139. static void appendstring(bpp, string)
  140. struct mbuf **bpp;
  141. char  *string;
  142. {
  143.   register struct mbuf *bp, *p;
  144.  
  145.   if (!*string) return;
  146.  
  147.   bp = (struct mbuf *) malloc(sizeof(struct mbuf ) + strlen(string) + 1);
  148.   bp->next = NULLMBUF;
  149.   bp->data = strcpy((char *) (bp + 1), string);
  150.  
  151.   if (*bpp) {
  152.     for (p = *bpp; p->next; p = p->next) ;
  153.     p->next = bp;
  154.   } else
  155.     *bpp = bp;
  156. }
  157.  
  158. /*---------------------------------------------------------------------------*/
  159.  
  160. static int  queuelength(bp)
  161. register struct mbuf *bp;
  162. {
  163.   register int  len;
  164.  
  165.   for (len = 0; bp; bp = bp->next)
  166.     len += strlen(bp->data);
  167.   return len;
  168. }
  169.  
  170. /*---------------------------------------------------------------------------*/
  171.  
  172. static void freequeue(bpp)
  173. struct mbuf **bpp;
  174. {
  175.   register struct mbuf *bp, *p;
  176.  
  177.   bp = *bpp;
  178.   while (p = bp) {
  179.     bp = bp->next;
  180.     free(p);
  181.   }
  182.   *bpp = NULLMBUF;
  183. }
  184.  
  185. /*---------------------------------------------------------------------------*/
  186.  
  187. static void free_connection(cp)
  188. register struct connection *cp;
  189. {
  190.   register struct permlink *p;
  191.  
  192.   for (p = permlinks; p; p = p->next)
  193.     if (p->connection == cp) p->connection = NULLCONNECTION;
  194.   if (cp->fmask) close(cp->fd);
  195.   freequeue(&cp->obuf);
  196.   free((char *) cp);
  197. }
  198.  
  199. /*---------------------------------------------------------------------------*/
  200.  
  201. static void free_closed_connections()
  202. {
  203.   register struct connection *cp, *p;
  204.  
  205.   for (p = NULLCONNECTION, cp = connections; cp; )
  206.     if (cp->type == CT_CLOSED ||
  207.     cp->type == CT_UNKNOWN && cp->time + 300 < currtime) {
  208.       if (p) {
  209.     p->next = cp->next;
  210.     free_connection(cp);
  211.     cp = p->next;
  212.       } else {
  213.     connections = cp->next;
  214.     free_connection(cp);
  215.     cp = connections;
  216.       }
  217.     } else {
  218.       p = cp;
  219.       cp = cp->next;
  220.     }
  221. }
  222.  
  223. /*---------------------------------------------------------------------------*/
  224.  
  225. static char  *getarg(line, all)
  226. char  *line;
  227. int  all;
  228. {
  229.  
  230.   char  *arg;
  231.   int  c;
  232.   static char  *p;
  233.  
  234.   if (line) p = line;
  235.   while (isspace(uchar(*p))) p++;
  236.   if (all) return p;
  237.   arg = p;
  238.   while (*p && !isspace(uchar(*p))) {
  239.     c = tolower(uchar(*p));
  240.     *p++ = c;
  241.   }
  242.   if (*p) *p++ = '\0';
  243.   return arg;
  244. }
  245.  
  246. /*---------------------------------------------------------------------------*/
  247.  
  248. static char  *formatline(prefix, text)
  249. char  *prefix, *text;
  250. {
  251.  
  252. #define PREFIXLEN 10
  253. #define LINELEN   79
  254.  
  255.   register char  *f, *t, *x;
  256.   register int  l, lw;
  257.  
  258.   static char  buf[2048];
  259.  
  260.   for (f = prefix, t = buf; *f; *t++ = *f++) ;
  261.   l = t - buf;
  262.   f = text;
  263.  
  264.   for (; ; ) {
  265.     while (isspace(uchar(*f))) f++;
  266.     if (!*f) {
  267.       *t++ = '\n';
  268.       *t = '\0';
  269.       return buf;
  270.     }
  271.     for (x = f; *x && !isspace(uchar(*x)); x++) ;
  272.     lw = x - f;
  273.     if (l > PREFIXLEN && l + 1 + lw > LINELEN) {
  274.       *t++ = '\n';
  275.       l = 0;
  276.     }
  277.     do {
  278.       *t++ = ' ';
  279.       l++;
  280.     } while (l < PREFIXLEN);
  281.     while (lw--) {
  282.       *t++ = *f++;
  283.       l++;
  284.     }
  285.   }
  286. }
  287.  
  288. /*---------------------------------------------------------------------------*/
  289.  
  290. static char  *timestring(gmt)
  291. long  gmt;
  292. {
  293.  
  294.   static char  buffer[80];
  295.   static char  monthnames[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
  296.   struct tm *tm;
  297.  
  298.   tm = localtime(&gmt);
  299.   if (gmt + 24 * 60 * 60 > currtime)
  300.     sprintf(buffer, " %2d:%02d", tm->tm_hour, tm->tm_min);
  301.   else
  302.     sprintf(buffer, "%-3.3s %2d", monthnames + 3 * tm->tm_mon, tm->tm_mday);
  303.   return buffer;
  304. }
  305.  
  306. /*---------------------------------------------------------------------------*/
  307.  
  308. static struct connection *alloc_connection(fd)
  309. int  fd;
  310. {
  311.  
  312.   int  flags;
  313.   struct connection *cp;
  314.  
  315.   if ((flags = fcntl(fd, F_GETFL, 0)) == -1) {
  316.     close(fd);
  317.     return 0;
  318.   }
  319.   if (fcntl(fd, F_SETFL, flags | O_NDELAY) == -1) {
  320.     close(fd);
  321.     return 0;
  322.   }
  323.   cp = (struct connection *) calloc(1, sizeof(struct connection ));
  324.   cp->fd = fd;
  325.   cp->fmask = (1 << fd);
  326.   cp->time = currtime;
  327.   cp->next = connections;
  328.   return connections = cp;
  329. }
  330.  
  331. /*---------------------------------------------------------------------------*/
  332.  
  333. static void accept_connect_request(flisten)
  334. int  flisten;
  335. {
  336.  
  337.   int  addrlen;
  338.   int  fd;
  339.   struct sockaddr addr;
  340.  
  341.   addrlen = sizeof(addr);
  342.   if ((fd = accept(flisten, &addr, &addrlen)) >= 0) alloc_connection(fd);
  343. }
  344.  
  345. /*---------------------------------------------------------------------------*/
  346.  
  347. static void clear_locks()
  348. {
  349.   register struct connection *p;
  350.  
  351.   for (p = connections; p; p = p->next) p->locked = 0;
  352. }
  353.  
  354. /*---------------------------------------------------------------------------*/
  355.  
  356. static void send_user_change_msg(name, host, oldchannel, newchannel)
  357. char  *name, *host;
  358. int  oldchannel, newchannel;
  359. {
  360.  
  361.   char  buffer[2048];
  362.   register struct connection *p;
  363.  
  364.   for (p = connections; p; p = p->next) {
  365.     if (p->type == CT_USER && !p->via && !p->locked) {
  366.       if (p->channel == oldchannel) {
  367.     if (newchannel >= 0)
  368.       sprintf(buffer, "*** %s switched to channel %d.\n", name, newchannel);
  369.     else
  370.       sprintf(buffer, "*** %s signed off.\n", name);
  371.     appendstring(&p->obuf, buffer);
  372.     p->locked = 1;
  373.       }
  374.       if (p->channel == newchannel) {
  375.     sprintf(buffer, "*** %s signed on.\n", name);
  376.     appendstring(&p->obuf, buffer);
  377.     p->locked = 1;
  378.       }
  379.     }
  380.     if (p->type == CT_HOST && !p->locked) {
  381.       sprintf(buffer, "/\377\200USER %s %s %d %d %d\n", name, host, 0, oldchannel, newchannel);
  382.       appendstring(&p->obuf, buffer);
  383.       p->locked = 1;
  384.     }
  385.   }
  386. }
  387.  
  388. /*---------------------------------------------------------------------------*/
  389.  
  390. static void send_msg_to_user(fromname, toname, text)
  391. char  *fromname, *toname, *text;
  392. {
  393.  
  394.   char  buffer[2048];
  395.   register struct connection *p;
  396.  
  397.   for (p = connections; p; p = p->next)
  398.     if (p->type == CT_USER && !strcmp(p->name, toname))
  399.       if (p->via) {
  400.     if (!p->via->locked) {
  401.       sprintf(buffer, "/\377\200UMSG %s %s %s\n", fromname, toname, text);
  402.       appendstring(&p->via->obuf, buffer);
  403.       p->via->locked = 1;
  404.     }
  405.       } else {
  406.     if (!p->locked) {
  407.       if (strcmp(fromname, "conversd")) {
  408.         sprintf(buffer, "<*%s*>:", fromname);
  409.         appendstring(&p->obuf, formatline(buffer, text));
  410.       } else {
  411.         appendstring(&p->obuf, text);
  412.         appendstring(&p->obuf, "\n");
  413.       }
  414.       p->locked = 1;
  415.     }
  416.       }
  417. }
  418.  
  419. /*---------------------------------------------------------------------------*/
  420.  
  421. static void send_msg_to_channel(fromname, channel, text)
  422. char  *fromname;
  423. int  channel;
  424. char  *text;
  425. {
  426.  
  427.   char  buffer[2048];
  428.   register struct connection *p;
  429.  
  430.   for (p = connections; p; p = p->next)
  431.     if (p->type == CT_USER && p->channel == channel)
  432.       if (p->via) {
  433.     if (!p->via->locked) {
  434.       sprintf(buffer, "/\377\200CMSG %s %d %s\n", fromname, channel, text);
  435.       appendstring(&p->via->obuf, buffer);
  436.       p->via->locked = 1;
  437.     }
  438.       } else {
  439.     if (!p->locked) {
  440.       sprintf(buffer, "<%s>:", fromname);
  441.       appendstring(&p->obuf, formatline(buffer, text));
  442.       p->locked = 1;
  443.     }
  444.       }
  445. }
  446.  
  447. /*---------------------------------------------------------------------------*/
  448.  
  449. static void send_invite_msg(fromname, toname, channel)
  450. char  *fromname, *toname;
  451. int  channel;
  452. {
  453.  
  454.   static char  invitetext[] = "\n\007\007*** Message from %s at %s ...\nPlease join convers channel %d.\n\007\007\n";
  455.  
  456.   static char  responsetext[] = "*** Invitation sent to %s @ %s.";
  457.  
  458.   char  buffer[2048];
  459.   int  fd;
  460.   struct connection *p;
  461.   struct stat stbuf;
  462.   struct utmp *up;
  463.  
  464.   for (p = connections; p; p = p->next)
  465.     if (p->type == CT_USER && !strcmp(p->name, toname)) {
  466.       if (p->channel == channel) {
  467.     clear_locks();
  468.     sprintf(buffer, "*** User %s is already on this channel.", toname);
  469.     send_msg_to_user("conversd", fromname, buffer);
  470.     return;
  471.       }
  472.       if (!p->via && !p->locked) {
  473.     sprintf(buffer, invitetext, fromname, timestring(currtime), channel);
  474.     appendstring(&p->obuf, buffer);
  475.     clear_locks();
  476.     sprintf(buffer, responsetext, toname, myhostname);
  477.     send_msg_to_user("conversd", fromname, buffer);
  478.     return;
  479.       }
  480.       if (p->via && !p->via->locked) {
  481.     sprintf(buffer, "/\377\200INVI %s %s %d\n", fromname, toname, channel);
  482.     appendstring(&p->via->obuf, buffer);
  483.     return;
  484.       }
  485.     }
  486.  
  487.   while (up = getutent())
  488.     if (up->ut_type == USER_PROCESS && !strcmp(up->ut_user, toname)) {
  489.       sprintf(buffer, "/dev/%s", up->ut_line);
  490.       if (stat(buffer, &stbuf)) continue;
  491.       if ((stbuf.st_mode & 2) != 2) continue;
  492.       if ((fd = open(buffer, O_WRONLY, 0644)) < 0) continue;
  493.       sprintf(buffer, invitetext, fromname, timestring(currtime), channel);
  494.       write(fd, buffer, (unsigned) strlen(buffer));
  495.       close(fd);
  496.       endutent();
  497.       clear_locks();
  498.       sprintf(buffer, responsetext, toname, myhostname);
  499.       send_msg_to_user("conversd", fromname, buffer);
  500.       return;
  501.     }
  502.   endutent();
  503.  
  504.   for (p = connections; p; p = p->next)
  505.     if (p->type == CT_HOST && !p->locked) {
  506.       sprintf(buffer, "/\377\200INVI %s %s %d\n", fromname, toname, channel);
  507.       appendstring(&p->obuf, buffer);
  508.     }
  509.  
  510. }
  511.  
  512. /*---------------------------------------------------------------------------*/
  513.  
  514. static void update_permlinks(name, cp)
  515. char  *name;
  516. struct connection *cp;
  517. {
  518.   register struct permlink *p;
  519.  
  520.   for (p = permlinks; p; p = p->next)
  521.     if (!strcmp(p->name, name)) {
  522.       p->connection = cp;
  523.       p->statetime = currtime;
  524.       p->tries = 0;
  525.       p->waittime = 60;
  526.       p->retrytime = currtime + p->waittime;
  527.     }
  528. }
  529.  
  530. /*---------------------------------------------------------------------------*/
  531.  
  532. static void connect_permlinks()
  533. {
  534.  
  535. #define MAX_WAITTIME   (60*60*3)
  536.  
  537.   char  buffer[2048];
  538.   int  addrlen;
  539.   int  fd;
  540.   register struct connection *cp;
  541.   register struct permlink *p;
  542.   struct sockaddr *addr;
  543.  
  544.   for (p = permlinks; p; p = p->next) {
  545.     if (p->connection || p->retrytime > currtime) continue;
  546.     p->tries++;
  547.     p->waittime <<= 1;
  548.     if (p->waittime > MAX_WAITTIME) p->waittime = MAX_WAITTIME;
  549.     p->retrytime = currtime + p->waittime;
  550.     if (!(addr = build_sockaddr(p->socket, &addrlen))) continue;
  551.     if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) continue;
  552.     if (connect(fd, addr, addrlen) || !(cp = alloc_connection(fd))) {
  553.       close(fd);
  554.       continue;
  555.     }
  556.     p->connection = cp;
  557.     if (*p->command) appendstring(&cp->obuf, p->command);
  558.     appendstring(&cp->obuf, "convers\n");
  559.     sprintf(buffer, "/\377\200HOST %s\n", myhostname);
  560.     appendstring(&cp->obuf, buffer);
  561.   }
  562. }
  563.  
  564. /*---------------------------------------------------------------------------*/
  565.  
  566. static void bye_command(cp)
  567. struct connection *cp;
  568. {
  569.   register struct connection *p;
  570.  
  571.   switch (cp->type) {
  572.   case CT_UNKNOWN:
  573.     cp->type = CT_CLOSED;
  574.     break;
  575.   case CT_USER:
  576.     cp->type = CT_CLOSED;
  577.     clear_locks();
  578.     send_user_change_msg(cp->name, cp->host, cp->channel, -1);
  579.     break;
  580.   case CT_HOST:
  581.     cp->type = CT_CLOSED;
  582.     update_permlinks(cp->name, NULLCONNECTION);
  583.     for (p = connections; p; p = p->next)
  584.       if (p->via == cp) {
  585.     p->type = CT_CLOSED;
  586.     clear_locks();
  587.     send_user_change_msg(p->name, p->host, p->channel, -1);
  588.       }
  589.     break;
  590.   case CT_CLOSED:
  591.     break;
  592.   }
  593. }
  594.  
  595. /*---------------------------------------------------------------------------*/
  596.  
  597. static void channel_command(cp)
  598. struct connection *cp;
  599. {
  600.  
  601.   char  *s;
  602.   char  buffer[2048];
  603.   int  newchannel;
  604.  
  605.   s = getarg(0, 0);
  606.   if (!*s) {
  607.     sprintf(buffer, "*** You are on channel %d.\n", cp->channel);
  608.     appendstring(&cp->obuf, buffer);
  609.     return;
  610.   }
  611.   newchannel = atoi(s);
  612.   if (newchannel < 0 || newchannel > MAXCHANNEL) {
  613.     sprintf(buffer, "*** Channel numbers must be in the range 0..%d.\n", MAXCHANNEL);
  614.     appendstring(&cp->obuf, buffer);
  615.     return;
  616.   }
  617.   if (newchannel == cp->channel) {
  618.     sprintf(buffer, "*** Already on channel %d.\n", cp->channel);
  619.     appendstring(&cp->obuf, buffer);
  620.     return;
  621.   }
  622.   send_user_change_msg(cp->name, cp->host, cp->channel, newchannel);
  623.   cp->channel = newchannel;
  624.   sprintf(buffer, "*** Now on channel %d.\n", cp->channel);
  625.   appendstring(&cp->obuf, buffer);
  626. }
  627.  
  628. /*---------------------------------------------------------------------------*/
  629.  
  630. static void help_command(cp)
  631. struct connection *cp;
  632. {
  633.   appendstring(&cp->obuf, "Commands may be abbreviated. Commands are:\n");
  634.  
  635.   appendstring(&cp->obuf, "/?                   Print help information\n");
  636.   appendstring(&cp->obuf, "/BYE                 Terminate the convers session\n");
  637.   appendstring(&cp->obuf, "/CHANNEL n           Switch to channel n\n");
  638.   appendstring(&cp->obuf, "/EXIT                Terminate the convers session\n");
  639.   appendstring(&cp->obuf, "/HELP                Print help information\n");
  640.   appendstring(&cp->obuf, "/INVITE user         Invite user to join your channel\n");
  641.   appendstring(&cp->obuf, "/LINKS [LONG]        List all connections to other hosts\n");
  642.   appendstring(&cp->obuf, "/MSG user text...    Send a private message to user\n");
  643.   appendstring(&cp->obuf, "/QUIT                Terminate the convers session\n");
  644.   appendstring(&cp->obuf, "/WHO [QUICK] [LONG]  List all users and their channel numbers\n");
  645.   appendstring(&cp->obuf, "/WRITE user text...  Send a private message to user\n");
  646.  
  647.   appendstring(&cp->obuf, "***\n");
  648. }
  649.  
  650. /*---------------------------------------------------------------------------*/
  651.  
  652. static void invite_command(cp)
  653. struct connection *cp;
  654. {
  655.   char  *toname;
  656.  
  657.   toname = getarg(0, 0);
  658.   if (*toname) send_invite_msg(cp->name, toname, cp->channel);
  659. }
  660.  
  661. /*---------------------------------------------------------------------------*/
  662.  
  663. static void links_command(cp)
  664. struct connection *cp;
  665. {
  666.  
  667.   char  buffer[2048];
  668.   char  tmp[80];
  669.   int  full;
  670.   struct connection *pc;
  671.   struct permlink *pp;
  672.  
  673.   full = *(getarg(0, 0));
  674.   appendstring(&cp->obuf, full ?
  675.     "Host     State         Since NextTry Tries Queue Receivd Xmitted\n" :
  676.     "Host     State         Since\n");
  677.   for (pc = connections; pc; pc = pc->next)
  678.     if (pc->type == CT_HOST) {
  679.       sprintf(buffer,
  680.           full ?
  681.         "%-8.8s %-12s %s               %5d %7d %7d\n" :
  682.         "%-8.8s %-12s %s\n",
  683.           pc->name,
  684.           "Connected",
  685.           timestring(pc->time),
  686.           queuelength(pc->obuf),
  687.           pc->received,
  688.           pc->xmitted);
  689.       appendstring(&cp->obuf, buffer);
  690.     }
  691.   for (pp = permlinks; pp; pp = pp->next)
  692.     if (!pp->connection || pp->connection->type != CT_HOST) {
  693.       strcpy(tmp, timestring(pp->retrytime)),
  694.       sprintf(buffer,
  695.           full ?
  696.         "%-8.8s %-12s %s  %s %5d\n" :
  697.         "%-8.8s %-12s %s\n",
  698.           pp->name,
  699.           pp->connection ? "Connecting" : "Disconnected",
  700.           timestring(pp->statetime),
  701.           tmp,
  702.           pp->tries);
  703.       appendstring(&cp->obuf, buffer);
  704.     }
  705.   appendstring(&cp->obuf, "***\n");
  706. }
  707.  
  708. /*---------------------------------------------------------------------------*/
  709.  
  710. static void msg_command(cp)
  711. struct connection *cp;
  712. {
  713.  
  714.   char  *toname, *text;
  715.   char  buffer[2048];
  716.   register struct connection *p;
  717.  
  718.   toname = getarg(0, 0);
  719.   text = getarg(0, 1);
  720.   if (!*text) return;
  721.   for (p = connections; p; p = p->next)
  722.     if (p->type == CT_USER && !strcmp(p->name, toname)) break;
  723.   if (!p) {
  724.     sprintf(buffer, "*** No such user: %s.\n", toname);
  725.     appendstring(&cp->obuf, buffer);
  726.   } else
  727.     send_msg_to_user(cp->name, toname, text);
  728. }
  729.  
  730. /*---------------------------------------------------------------------------*/
  731.  
  732. static void name_command(cp)
  733. struct connection *cp;
  734. {
  735.  
  736.   char  buffer[2048];
  737.   int  newchannel;
  738.  
  739.   strcpy(cp->name, getarg(0, 0));
  740.   if (!*cp->name) return;
  741.   cp->type = CT_USER;
  742.   strcpy(cp->host, myhostname);
  743.   sprintf(buffer, "conversd @ %s $Revision: 2.17 $  Type /HELP for help.\n", myhostname);
  744.   appendstring(&cp->obuf, buffer);
  745.   newchannel = atoi(getarg(0, 0));
  746.   if (newchannel < 0 || newchannel > MAXCHANNEL) {
  747.     sprintf(buffer, "*** Channel numbers must be in the range 0..%d.\n", MAXCHANNEL);
  748.     appendstring(&cp->obuf, buffer);
  749.   } else
  750.     cp->channel = newchannel;
  751.   send_user_change_msg(cp->name, cp->host, -1, cp->channel);
  752. }
  753.  
  754. /*---------------------------------------------------------------------------*/
  755.  
  756. static void who_command(cp)
  757. struct connection *cp;
  758. {
  759.  
  760.   char  buffer[2048];
  761.   int  channel;
  762.   int  full = 0;
  763.   int  quick = 0;
  764.   struct connection *p;
  765.  
  766.   switch (*(getarg(0, 0))) {
  767.   case 'l':
  768.     full = 1;
  769.     break;
  770.   case 'q':
  771.     quick = 1;
  772.     break;
  773.   }
  774.  
  775.   if (quick) {
  776.     appendstring(&cp->obuf, "Channel Users\n");
  777.     clear_locks();
  778.     do {
  779.       channel = -1;
  780.       for (p = connections; p; p = p->next)
  781.     if (p->type == CT_USER && !p->locked && (channel < 0 || channel == p->channel)) {
  782.       if (channel < 0) {
  783.         channel = p->channel;
  784.         sprintf(buffer, "%7d", channel);
  785.       }
  786.       strcat(buffer, " ");
  787.       strcat(buffer, p->name);
  788.       p->locked = 1;
  789.     }
  790.       if (channel >= 0) {
  791.     strcat(buffer, "\n");
  792.     appendstring(&cp->obuf, buffer);
  793.       }
  794.     } while (channel >= 0);
  795.     appendstring(&cp->obuf, "***\n");
  796.     return;
  797.   }
  798.  
  799.   appendstring(&cp->obuf, full ?
  800.       "User     Host     Via      Channel   Time Queue Receivd Xmitted\n" :
  801.       "User     Host     Via      Channel   Time\n");
  802.   for (p = connections; p; p = p->next)
  803.     if (p->type == CT_USER) {
  804.       sprintf(buffer,
  805.           full ?
  806.         "%-8.8s %-8.8s %-8.8s %7d %s %5d %7d %7d\n" :
  807.         "%-8.8s %-8.8s %-8.8s %7d %s\n",
  808.           p->name,
  809.           p->host,
  810.           p->via ? p->via->name : "",
  811.           p->channel,
  812.           timestring(p->time),
  813.           queuelength(p->obuf),
  814.           p->received,
  815.           p->xmitted);
  816.       appendstring(&cp->obuf, buffer);
  817.     }
  818.   appendstring(&cp->obuf, "***\n");
  819. }
  820.  
  821. /*---------------------------------------------------------------------------*/
  822.  
  823. static void h_cmsg_command(cp)
  824. struct connection *cp;
  825. {
  826.  
  827.   char  *name;
  828.   char  *text;
  829.   int  channel;
  830.  
  831.   name = getarg(0, 0);
  832.   channel = atoi(getarg(0, 0));
  833.   text = getarg(0, 1);
  834.   if (*text) send_msg_to_channel(name, channel, text);
  835. }
  836.  
  837. /*---------------------------------------------------------------------------*/
  838.  
  839. static void h_host_command(cp)
  840. struct connection *cp;
  841. {
  842.  
  843.   char  *name;
  844.   char  buffer[2048];
  845.   register struct connection *p;
  846.   register struct permlink *pp;
  847.  
  848.   name = getarg(0, 0);
  849.   if (!*name) return;
  850.   for (p = connections; p; p = p->next)
  851.     if (!strcmp(p->name, name)) bye_command(p);
  852.   for (pp = permlinks; pp; pp = pp->next)
  853.     if (!strcmp(pp->name, name) && pp->connection && pp->connection != cp)
  854.       bye_command((strcmp(myhostname, name) < 0) ? pp->connection : cp);
  855.   if (cp->type != CT_UNKNOWN) return;
  856.   cp->type = CT_HOST;
  857.   strcpy(cp->name, name);
  858.   update_permlinks(name, cp);
  859.   sprintf(buffer, "/\377\200HOST %s\n", myhostname);
  860.   appendstring(&cp->obuf, buffer);
  861.   for (p = connections; p; p = p->next)
  862.     if (p->type == CT_USER) {
  863.       sprintf(buffer, "/\377\200USER %s %s %d %d %d\n", p->name, p->host, 0, -1, p->channel);
  864.       appendstring(&cp->obuf, buffer);
  865.     }
  866. }
  867.  
  868. /*---------------------------------------------------------------------------*/
  869.  
  870. static void h_invi_command(cp)
  871. struct connection *cp;
  872. {
  873.  
  874.   char  *fromname, *toname;
  875.   int  channel;
  876.  
  877.   fromname = getarg(0, 0);
  878.   toname = getarg(0, 0);
  879.   channel = atoi(getarg(0, 0));
  880.   send_invite_msg(fromname, toname, channel);
  881. }
  882.  
  883. /*---------------------------------------------------------------------------*/
  884.  
  885. static void h_umsg_command(cp)
  886. struct connection *cp;
  887. {
  888.   char  *fromname, *toname, *text;
  889.  
  890.   fromname = getarg(0, 0);
  891.   toname = getarg(0, 0);
  892.   text = getarg(0, 1);
  893.   if (*text) send_msg_to_user(fromname, toname, text);
  894. }
  895.  
  896. /*---------------------------------------------------------------------------*/
  897.  
  898. static void h_user_command(cp)
  899. struct connection *cp;
  900. {
  901.  
  902.   char  *host;
  903.   char  *name;
  904.   int  newchannel;
  905.   int  oldchannel;
  906.   register struct connection *p;
  907.  
  908.   name = getarg(0, 0);
  909.   host = getarg(0, 0);
  910.   getarg(0, 0);            /*** ignore this argument, protocol has changed ***/
  911.   oldchannel = atoi(getarg(0, 0));
  912.   newchannel = atoi(getarg(0, 0));
  913.  
  914.   for (p = connections; p; p = p->next)
  915.     if (p->type == CT_USER       &&
  916.     p->channel == oldchannel &&
  917.     p->via == cp             &&
  918.     !strcmp(p->name, name)   &&
  919.     !strcmp(p->host, host))  break;
  920.   if (!p) {
  921.     p = (struct connection *) calloc(1, sizeof(struct connection ));
  922.     p->type = CT_USER;
  923.     strcpy(p->name, name);
  924.     strcpy(p->host, host);
  925.     p->via = cp;
  926.     p->channel = oldchannel;
  927.     p->time = currtime;
  928.     p->next = connections;
  929.     connections = p;
  930.   }
  931.   if ((p->channel = newchannel) < 0) p->type = CT_CLOSED;
  932.   send_user_change_msg(name, host, oldchannel, newchannel);
  933. }
  934.  
  935. /*---------------------------------------------------------------------------*/
  936.  
  937. static void process_input(cp)
  938. struct connection *cp;
  939. {
  940.  
  941.   static struct cmdtable {
  942.     char  *name;
  943.     void (*fnc)();
  944.     int  states;
  945.   } cmdtable[] = {
  946.  
  947.     "?",          help_command,       CM_USER,
  948.     "bye",        bye_command,        CM_USER,
  949.     "channel",    channel_command,    CM_USER,
  950.     "exit",       bye_command,        CM_USER,
  951.     "help",       help_command,       CM_USER,
  952.     "invite",     invite_command,     CM_USER,
  953.     "links",      links_command,      CM_USER,
  954.     "msg",        msg_command,        CM_USER,
  955.     "name",       name_command,       CM_UNKNOWN,
  956.     "quit",       bye_command,        CM_USER,
  957.     "who",        who_command,        CM_USER,
  958.     "write",      msg_command,        CM_USER,
  959.  
  960.     "\377\200cmsg", h_cmsg_command,   CM_HOST,
  961.     "\377\200host", h_host_command,   CM_UNKNOWN,
  962.     "\377\200invi", h_invi_command,   CM_HOST,
  963.     "\377\200umsg", h_umsg_command,   CM_HOST,
  964.     "\377\200user", h_user_command,   CM_HOST,
  965.  
  966.     0, 0, 0
  967.   };
  968.  
  969.   char  *arg;
  970.   char  buffer[2048];
  971.   int  arglen;
  972.   struct cmdtable *cmdp;
  973.  
  974.   clear_locks();
  975.   cp->locked = 1;
  976.  
  977.   if (*cp->ibuf == '/') {
  978.     arglen = strlen(arg = getarg(cp->ibuf + 1, 0));
  979.     for (cmdp = cmdtable; cmdp->name; cmdp++)
  980.       if (!strncmp(cmdp->name, arg, arglen)) {
  981.     if (cmdp->states & (1 << cp->type)) (*cmdp->fnc)(cp);
  982.     return;
  983.       }
  984.     if (cp->type == CT_USER) {
  985.       sprintf(buffer, "*** Unknown command '/%s'. Type /HELP for help.\n", arg);
  986.       appendstring(&cp->obuf, buffer);
  987.     }
  988.     return;
  989.   }
  990.  
  991.   if (cp->type == CT_USER)
  992.     send_msg_to_channel(cp->name, cp->channel, cp->ibuf);
  993. }
  994.  
  995. /*---------------------------------------------------------------------------*/
  996.  
  997. static void read_configuration()
  998. {
  999.  
  1000.   FILE * fp;
  1001.   char  *conffile = "/tcp/convers.conf";
  1002.   char  *host_name, *sock_name;
  1003.   char  line[1024];
  1004.   struct permlink *p;
  1005.  
  1006.   if (!(fp = fopen(conffile, "r"))) return;
  1007.   if (fgets(line, sizeof(line), fp)) {
  1008.     host_name = getarg(line, 0);
  1009.     if (*host_name)
  1010.       myhostname = strcpy(malloc((unsigned) (strlen(host_name) + 1)), host_name);
  1011.   }
  1012.   while (fgets(line, sizeof(line), fp)) {
  1013.     host_name = getarg(line, 0);
  1014.     sock_name = getarg(0, 0);
  1015.     if (*host_name && *sock_name) {
  1016.       p = (struct permlink *) calloc(1, sizeof(struct permlink ));
  1017.       strcpy(p->name, host_name);
  1018.       strcpy(p->socket, sock_name);
  1019.       strcpy(p->command, getarg(0, 1));
  1020.       p->next = permlinks;
  1021.       permlinks = p;
  1022.       update_permlinks(host_name, NULLCONNECTION);
  1023.     }
  1024.   }
  1025.   fclose(fp);
  1026. }
  1027.  
  1028. /*---------------------------------------------------------------------------*/
  1029.  
  1030. main(argc, argv)
  1031. int  argc;
  1032. char  **argv;
  1033. {
  1034.  
  1035.   static char  *socketnames[] = {
  1036. #ifdef HPUX
  1037.     "unix:/tcp/sockets/convers",
  1038. #else 
  1039.     "*:3600",
  1040. #endif /* HPUX */
  1041. /** "*:convers",                  Currently not used **/
  1042.     (char *) 0
  1043.   };
  1044.  
  1045.   static struct timeval select_timeout = {
  1046.     60, 0
  1047.   };
  1048.  
  1049.   char  buffer[2048];
  1050.   int  addrlen;
  1051.   int  arg;
  1052.   int  flisten[_NFILE], flistenmask[_NFILE];
  1053.   int  i;
  1054.   int  nfd, rmask, wmask;
  1055.   int  size;
  1056.   struct connection *cp;
  1057.   struct mbuf *bp;
  1058. #if (defined (HPUX)||defined(BSD))
  1059.   struct sigvec vec;
  1060. #endif
  1061.   struct sockaddr *addr;
  1062.  
  1063.   umask(022);
  1064.   for (i = 0; i < _NFILE; i++) close(i);
  1065.   chdir("/");
  1066.   setpgrp();
  1067. #if (defined(HPUX)||defined(BSD))
  1068.   vec.sv_mask = vec.sv_flags = 0;
  1069.   vec.sv_handler = sigpipe_handler;
  1070.   sigvector(SIGPIPE, &vec, (struct sigvec *) 0);
  1071. #endif
  1072.   if (!getenv("TZ")) putenv("TZ=MEZ-1MESZ");
  1073.   uname(&utsname);
  1074.   myhostname = utsname.nodename;
  1075.   time(&currtime);
  1076.  
  1077.   if (argc < 2) {
  1078.     read_configuration();
  1079.   } else {
  1080.     socketnames[0] = argv[1];
  1081.     socketnames[1] = (char *) 0;
  1082.   }
  1083.  
  1084.   for (i = 0; socketnames[i]; i++) {
  1085.     flistenmask[i] = 0;
  1086.     if (addr = build_sockaddr(socketnames[i], &addrlen)) {
  1087.       if ((flisten[i] = socket(addr->sa_family, SOCK_STREAM, 0)) >= 0) {
  1088.     switch (addr->sa_family) {
  1089.     case AF_UNIX:
  1090.       unlink(addr->sa_data);
  1091.       break;
  1092.     case AF_INET:
  1093.       arg = 1;
  1094.       setsockopt(flisten[i], SOL_SOCKET, SO_REUSEADDR, (char *) &arg, sizeof(arg));
  1095.       break;
  1096.     }
  1097.     if (!bind(flisten[i], addr, addrlen) && !listen(flisten[i], SOMAXCONN)) {
  1098.       flistenmask[i] = (1 << flisten[i]);
  1099.     } else {
  1100.       close(flisten[i]);
  1101.     }
  1102.       }
  1103.     }
  1104.   }
  1105.  
  1106.   for (; ; ) {
  1107.  
  1108.     free_closed_connections();
  1109.  
  1110.     connect_permlinks();
  1111.  
  1112.     nfd = rmask = wmask = 0;
  1113.     for (i = 0; socketnames[i]; i++)
  1114.       if (flistenmask[i]) {
  1115.     if (nfd <= flisten[i]) nfd = flisten[i] + 1;
  1116.     rmask |= flistenmask[i];
  1117.       }
  1118.     for (cp = connections; cp; cp = cp->next) {
  1119.       if (nfd <= cp->fd) nfd = cp->fd + 1;
  1120.       rmask |= cp->fmask;
  1121.       if (cp->obuf) wmask |= cp->fmask;
  1122.     }
  1123.     if (select(nfd, &rmask, &wmask, (int *) 0, &select_timeout) < 1)
  1124.       rmask = wmask = 0;
  1125.  
  1126.     time(&currtime);
  1127.  
  1128.     for (i = 0; socketnames[i]; i++)
  1129.       if (rmask & flistenmask[i]) accept_connect_request(flisten[i]);
  1130.  
  1131.     for (cp = connections; cp; cp = cp->next) {
  1132.  
  1133.       if (rmask & cp->fmask)
  1134.     if ((size = read(cp->fd, buffer, sizeof(buffer))) <= 0)
  1135.       bye_command(cp);
  1136.     else {
  1137.       cp->received += size;
  1138.       for (i = 0; i < size; i++)
  1139.         switch (buffer[i]) {
  1140.         case '\b':
  1141.           if (cp->icnt) cp->icnt--;
  1142.           break;
  1143.         case '\n':
  1144.         case '\r':
  1145.           if (cp->icnt) {
  1146.         cp->ibuf[cp->icnt] = '\0';
  1147.         process_input(cp);
  1148.         cp->icnt = 0;
  1149.           }
  1150.           break;
  1151.         default:
  1152.           if (cp->icnt < sizeof(cp->ibuf) - 5)
  1153.         cp->ibuf[cp->icnt++] = buffer[i];
  1154.           break;
  1155.         }
  1156.     }
  1157.  
  1158.       if (wmask & cp->fmask) {
  1159.     size = write(cp->fd, cp->obuf->data, (unsigned) strlen(cp->obuf->data));
  1160.     if (size < 0)
  1161.       bye_command(cp);
  1162.     else {
  1163.       cp->xmitted += size;
  1164.       cp->obuf->data += size;
  1165.       while ((bp = cp->obuf) && !*cp->obuf->data) {
  1166.         cp->obuf = cp->obuf->next;
  1167.         free(bp);
  1168.       }
  1169.     }
  1170.       }
  1171.  
  1172.     }
  1173.   }
  1174. }
  1175.  
  1176.